home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / proc / procDebug.c < prev    next >
C/C++ Source or Header  |  1991-04-28  |  17KB  |  614 lines

  1. /*
  2.  *  procDebug.c --
  3.  *
  4.  *    Routines to debug a process.  This file maintains a monitor that 
  5.  *    synchronizes access to the debug list.  Routines in this monitor
  6.  *    are responsible for the following fields in the proc table:
  7.  *
  8.  *        PROC_DEBUGGED, PROC_ON_DEBUG_LIST, PROC_SINGLE_STEP_FLAG,
  9.  *           and PROC_DEBUG_WAIT can be set in the genFlags field.
  10.  *
  11.  *    The PROC_DEBUGGED flag is set when a process is being actively debugged
  12.  *    by a debugger.  It is not cleared until a debugger issues the
  13.  *    PROC_DETACH_DEBUGGER debug command.  The PROC_ON_DEBUG_LIST flag is
  14.  *    set when a process is put onto the debug queue and cleared when
  15.  *    it is taken off.
  16.  *
  17.  * Copyright 1986, 1988 Regents of the University of California
  18.  * Permission to use, copy, modify, and distribute this
  19.  * software and its documentation for any purpose and without
  20.  * fee is hereby granted, provided that the above copyright
  21.  * notice appear in all copies.  The University of California
  22.  * makes no representations about the suitability of this
  23.  * software for any purpose.  It is provided "as is" without
  24.  * express or implied warranty.
  25.  */
  26.  
  27. #ifndef lint
  28. static char rcsid[] = "$Header: /sprite/src/kernel/proc/RCS/procDebug.c,v 9.6 90/09/12 13:57:49 jhh Exp $ SPRITE (Berkeley)";
  29. #endif /* not lint */
  30.  
  31. #include <sprite.h>
  32. #include <proc.h>
  33. #include <procInt.h>
  34. #include <procMigrate.h>
  35. #include <status.h>
  36. #include <sync.h>
  37. #include <sched.h>
  38. #include <sys.h>
  39. #include <list.h>
  40. #include <stdlib.h>
  41. #include <vm.h>
  42.  
  43. Sync_Condition    debugListCondition;    /* Condition to sleep on when
  44.                          * waiting for a process to go
  45.                          * onto the debug list. */
  46. static Sync_Lock debugLock;             /* Monitor lock. */
  47. #define LOCKPTR &debugLock
  48.  
  49. List_Links    debugListHdr;
  50. List_Links    *debugList = &debugListHdr;
  51.  
  52. static    ENTRY    void        AddToDebugList _ARGS_((
  53.                     Proc_ControlBlock *procPtr));
  54. static    ENTRY    void        RemoveFromDebugList _ARGS_((
  55.                     Proc_ControlBlock *procPtr));
  56. static    ENTRY    ReturnStatus    ProcGetThisDebug _ARGS_((Proc_PID pid,
  57.                     Proc_ControlBlock **procPtrPtr));
  58. static    ENTRY    ReturnStatus    ProcGetNextDebug _ARGS_((Address destAddr,
  59.                     Proc_ControlBlock **procPtrPtr));
  60.  
  61.  
  62. /*
  63.  *----------------------------------------------------------------------
  64.  *
  65.  * Proc_DebugInit --
  66.  *
  67.  *    Initialize the debug list.
  68.  *
  69.  * Results:
  70.  *    None.
  71.  *
  72.  * Side effects:
  73.  *    The debug list is initialized.
  74.  *
  75.  *----------------------------------------------------------------------
  76.  */
  77.  
  78. void
  79. ProcDebugInit()
  80. {
  81.     List_Init(debugList);
  82.     Sync_LockInitDynamic(&debugLock, "Proc:debugLock");
  83. }
  84.  
  85.  
  86. /*
  87.  *----------------------------------------------------------------------
  88.  *
  89.  * Proc_Debug --
  90.  *
  91.  *    This routine is used to debug a process. This routine is not
  92.  *    inside the monitor. 
  93.  *
  94.  * Results:
  95.  *    SYS_INVALID_ARG -     buffer address was invalid.
  96.  *    PROC_INVALID_PID -     The pid was out-of-range or specified a
  97.  *                non-existent process.
  98.  *    SYS_ARG_NOACCESS -     The buffers were not accessible.
  99.  *
  100.  * Side effects:
  101.  *    The process state and address space may be updated.
  102.  *    A process may be removed from the debug list.
  103.  *
  104.  *----------------------------------------------------------------------
  105.  */
  106.  
  107. ReturnStatus
  108. Proc_Debug(pid, request, numBytes, srcAddr, destAddr)
  109.     Proc_PID         pid;        /* Process id of the process to be 
  110.                      * debugged. */
  111.     Proc_DebugReq     request;     /* Type of action on the debugged 
  112.                      * process. */
  113.     int         numBytes;    /* # of bytes of info to be read or 
  114.                      * written. */
  115.     Address         srcAddr;    /* Location (either in caller or pid) 
  116.                      * where info is to be read. */
  117.     Address         destAddr;    /* Location (either in caller or pid) 
  118.                      * where info info is to be written. */
  119. {
  120.     register Proc_ControlBlock     *procPtr = (Proc_ControlBlock *) NIL;
  121.     Proc_DebugState        debugState;
  122.     int                i;
  123.     ReturnStatus        status = SUCCESS;
  124.     Proc_ControlBlock        *tProcPtr;
  125.  
  126.     /*
  127.      * If the caller is trying to manipulate a debugged process make sure that
  128.      * the process is actually in the debug state.
  129.      */
  130.     if (request != PROC_GET_NEXT_DEBUG && request != PROC_GET_THIS_DEBUG) {
  131.     procPtr = Proc_LockPID(pid);
  132.     if (procPtr == (Proc_ControlBlock *) NIL || 
  133.         !(procPtr->genFlags & PROC_DEBUGGED) ||
  134.         (procPtr->genFlags & PROC_ON_DEBUG_LIST) ||
  135.         procPtr->state != PROC_SUSPENDED ||
  136.         ((procPtr->genFlags & PROC_KILLING) && request==PROC_CONTINUE)) {
  137.         if (procPtr != (Proc_ControlBlock *) NIL) {
  138.         Proc_Unlock(procPtr);
  139.         }
  140.         return (PROC_INVALID_PID);
  141.     }
  142.     }
  143.  
  144.     switch (request) {
  145.     case PROC_GET_THIS_DEBUG:
  146.         status = ProcGetThisDebug(pid, &tProcPtr);
  147.         procPtr = tProcPtr;
  148.         break;
  149.         
  150.     case PROC_GET_NEXT_DEBUG: {
  151.         status = ProcGetNextDebug(destAddr, &tProcPtr);
  152.         procPtr = tProcPtr;
  153.         break;
  154.     }
  155.  
  156.     case PROC_SINGLE_STEP:
  157.             procPtr->genFlags |= PROC_SINGLE_STEP_FLAG;
  158.         procPtr->specialHandling = 1;
  159.         /* Fall through to ... */
  160.         
  161.     case PROC_CONTINUE:
  162.         Sched_MakeReady(procPtr);
  163.         break;
  164.  
  165.     case PROC_GET_DBG_STATE:
  166.  
  167.         debugState.processID    = procPtr->processID;
  168.         debugState.termReason    = procPtr->termReason;
  169.         debugState.termStatus    = procPtr->termStatus;
  170.         debugState.termCode        = procPtr->termCode;
  171.         Mach_GetDebugState(procPtr, &debugState);
  172.         debugState.sigHoldMask    = procPtr->sigHoldMask;
  173.         debugState.sigPendingMask    = procPtr->sigPendingMask;
  174.         for (i = 0; i < SIG_NUM_SIGNALS; i++) {
  175.         debugState.sigActions[i]    = procPtr->sigActions[i];
  176.         debugState.sigMasks[i]        = procPtr->sigMasks[i];
  177.         debugState.sigCodes[i]        = procPtr->sigCodes[i];
  178.         }
  179.  
  180.         if (Vm_CopyOut(sizeof(Proc_DebugState), (Address) &debugState, 
  181.                destAddr)) {
  182.         status = SYS_ARG_NOACCESS;
  183.         }
  184.         break;
  185.  
  186.     case PROC_SET_DBG_STATE:
  187.  
  188.         if (Vm_CopyIn(sizeof(Proc_DebugState), srcAddr, 
  189.                 (Address) &debugState)) {
  190.         status = SYS_ARG_NOACCESS;
  191.         } else {
  192.         Mach_SetDebugState(procPtr, &debugState);
  193.         Sig_ChangeState(procPtr, debugState.sigActions,
  194.                 debugState.sigMasks, debugState.sigPendingMask,
  195.                 debugState.sigCodes, debugState.sigHoldMask);
  196.         }
  197.         break;
  198.  
  199. #define MAX_REQUEST_SIZE 16384
  200.  
  201.     case PROC_READ:
  202.         if (numBytes > MAX_REQUEST_SIZE) {
  203.         status = SYS_INVALID_ARG;
  204.         } else {
  205.         /*
  206.          * Read from the debuggee to the debugger.
  207.          */
  208.         status = Vm_CopyInProc(numBytes, procPtr, srcAddr, 
  209.                        destAddr, FALSE);
  210.         }
  211.  
  212.         break;
  213.  
  214.     case PROC_WRITE:
  215.         if (numBytes > MAX_REQUEST_SIZE) {
  216.         status = SYS_INVALID_ARG;
  217.         break;
  218.         }
  219.  
  220.         /*
  221.          * Make sure that the range of bytes is writable.
  222.          */
  223.         Vm_ChangeCodeProt(procPtr, destAddr, numBytes, TRUE);
  224.         /*
  225.          * Write from the debugger to the debuggee.
  226.          */
  227.         status = Vm_CopyOutProc(numBytes, srcAddr, FALSE,
  228.                     procPtr, destAddr);
  229.         /*
  230.          * Change the protection back.
  231.          */
  232.         Vm_ChangeCodeProt(procPtr, destAddr, numBytes, FALSE);
  233.         Vm_FlushCode(procPtr, destAddr, numBytes);
  234.  
  235.         break;
  236.  
  237.     case PROC_DETACH_DEBUGGER:
  238.         /*
  239.          * Detach from this process.  This has the side effect of 
  240.          * continuing the process as if a resume signal had been sent.
  241.          */
  242.         procPtr->genFlags &= ~(PROC_DEBUGGED | PROC_DEBUG_WAIT);
  243.         Sched_MakeReady(procPtr);
  244.         procPtr->termReason = PROC_TERM_RESUMED;
  245.         procPtr->termStatus = SIG_RESUME;
  246.         procPtr->termCode = SIG_NO_CODE;
  247.         Proc_InformParent(procPtr, PROC_RESUME_STATUS);
  248.         break;
  249.  
  250.     default:
  251.         status = SYS_INVALID_ARG;
  252.         break;
  253.     }
  254.  
  255.     if (status != GEN_ABORTED_BY_SIGNAL && status != PROC_INVALID_PID) {
  256.     Proc_Unlock(procPtr);
  257.     }
  258.  
  259.     return(status);
  260. }
  261.  
  262.  
  263. /*
  264.  *----------------------------------------------------------------------
  265.  *
  266.  * Proc_SuspendProcess --
  267.  *
  268.  *    Put the process into the suspended state.  If the process is
  269.  *    entering the suspended state because of a bug and no process is 
  270.  *    debugging it then put it onto the debug list.
  271.  *
  272.  * Results:
  273.  *    None.
  274.  *
  275.  * Side effects:
  276.  *    The process state is changed and the process may be put onto
  277.  *    the debug list. A context switch is performed to the suspend state.
  278.  *
  279.  *----------------------------------------------------------------------
  280.  */
  281. void
  282. Proc_SuspendProcess(procPtr, debug, termReason, termStatus, termCode)
  283.     register    Proc_ControlBlock    *procPtr;    /* Process to put on the
  284.                              * debug list. */
  285.     Boolean                debug;        /* TRUE => this process
  286.                              * is being suspended
  287.                              * because of an 
  288.                              * error. */
  289.     int                    termReason;    /* Reason why process
  290.                              * went to this state.*/
  291.     int                    termStatus;    /* Termination status.*/
  292.     int                    termCode;    /* Termination code. */
  293. {
  294.     Boolean foreign = (procPtr->genFlags & PROC_FOREIGN);
  295.  
  296.     Proc_Lock(procPtr);
  297.     procPtr->termReason    = termReason;
  298.     procPtr->termStatus    = termStatus;
  299.     procPtr->termCode    = termCode;
  300.  
  301.     if (debug &&  foreign &&
  302.     proc_KillMigratedDebugs) {
  303.     if (proc_MigDebugLevel > 0) {
  304.         panic("Migrated process being placed on debug list.\n");
  305.     }
  306.     }
  307.  
  308.     if (debug) {
  309.     if (!(procPtr->genFlags & PROC_DEBUGGED)) {
  310.         /*
  311.          * If the process isn't currently being debugged then it goes on 
  312.          * the debug list and its parent is notified of a state change.
  313.          */
  314.         AddToDebugList(procPtr);
  315.         Proc_InformParent(procPtr, PROC_SUSPEND_STATUS);
  316.         ProcDebugWakeup();
  317.     } else if (procPtr->genFlags & PROC_DEBUG_WAIT) {
  318.         /*
  319.          * A process is waiting for this process so wake it up.
  320.          */
  321.         ProcDebugWakeup();
  322.     }
  323.     } else {
  324.     /*
  325.      * The process is being suspended.  Notify the parent and then wakeup
  326.      * anyone waiting for this process to enter the debug state.
  327.      */
  328.     Proc_InformParent(procPtr, PROC_SUSPEND_STATUS);
  329.     if (procPtr->genFlags & PROC_DEBUG_WAIT) {
  330.         ProcDebugWakeup();
  331.     }
  332.     }
  333.     if (foreign) {
  334.     ProcRemoteSuspend(procPtr, PROC_SUSPEND_STATUS);
  335.     }
  336.     Proc_Unlock(procPtr);
  337.     Sched_ContextSwitch(PROC_SUSPENDED);
  338. }
  339.  
  340.  
  341. /*
  342.  *----------------------------------------------------------------------
  343.  *
  344.  * Proc_ResumeProcess --
  345.  *
  346.  *    Resume execution of the given process.  It is assumed that this 
  347.  *    procedure is called with the process table entry locked.
  348.  *
  349.  * Results:
  350.  *    None.
  351.  *
  352.  * Side effects:
  353.  *    The process may be made runnable and may be removed from the debug list.
  354.  *
  355.  *----------------------------------------------------------------------
  356.  */
  357. void
  358. Proc_ResumeProcess(procPtr, killingProc)
  359.     register    Proc_ControlBlock    *procPtr;    /* Process to remove
  360.                              * from list. */
  361.     Boolean                killingProc;    /* This process is
  362.                              * being resumed for
  363.                              * the purpose of 
  364.                              * killing it. */
  365. {
  366.     if (procPtr->state == PROC_SUSPENDED &&
  367.         (killingProc || !(procPtr->genFlags & PROC_DEBUGGED))) {
  368.     /*
  369.      * Only processes that are currently suspended and are either being
  370.      * killed or aren't being actively debugged can be resumed.
  371.      */
  372.     RemoveFromDebugList(procPtr);
  373.     if (procPtr->genFlags & PROC_DEBUGGED) {
  374.         procPtr->genFlags |= PROC_KILLING;
  375.     }
  376.     if (procPtr->genFlags & PROC_DEBUG_WAIT) {
  377.         ProcDebugWakeup();
  378.     }
  379.     procPtr->genFlags &= ~PROC_DEBUG_WAIT;
  380.     Sched_MakeReady(procPtr);
  381.     if (!killingProc) {
  382.         procPtr->termReason = PROC_TERM_RESUMED;
  383.         procPtr->termStatus = SIG_RESUME;
  384.         procPtr->termCode = SIG_NO_CODE;
  385.         /*
  386.          * The parent is notified in background because we are called
  387.          * by the signal code as part of the act of sending a signal
  388.          * and if a SIG_CHILD happens now we will have deadlock.
  389.          * If the process is remote, send the term flags over and
  390.          * let the home node handle signalling the parent.
  391.          */
  392.         if (procPtr->genFlags & PROC_FOREIGN) {
  393.         ProcRemoteSuspend(procPtr, PROC_RESUME_STATUS);
  394.         } else {
  395.         Proc_InformParent(procPtr, PROC_RESUME_STATUS);
  396.         }
  397.     }
  398.     }
  399.  
  400. }
  401.  
  402.  
  403. /*
  404.  *----------------------------------------------------------------------
  405.  *
  406.  * ProcDebugWakeup --
  407.  *
  408.  *    Wakeup any processes waiting on the debug list.
  409.  *
  410.  * Results:
  411.  *    None.
  412.  *
  413.  * Side effects:
  414.  *    None.
  415.  *
  416.  *----------------------------------------------------------------------
  417.  */
  418. ENTRY void
  419. ProcDebugWakeup()
  420. {
  421.     LOCK_MONITOR;
  422.     Sync_Broadcast(&debugListCondition);
  423.     UNLOCK_MONITOR;
  424. }
  425.  
  426. /*
  427.  *----------------------------------------------------------------------
  428.  *
  429.  * ProcGetThisDebug --
  430.  *
  431.  *    Get the specified process on the debug list. If it isn't there
  432.  *    then wait for it to show up.
  433.  *
  434.  * Results:
  435.  *    PROC_INVALID_PID if process doesn't exist or is dieing.
  436.  *    GEN_ABORTED_BY_SIGNAL if wait for process was interrupted by a 
  437.  *        signal
  438.  *
  439.  *
  440.  * Side effects:
  441.  *    Process may be locked.
  442.  *
  443.  *----------------------------------------------------------------------
  444.  */
  445.  
  446. static ENTRY ReturnStatus
  447. ProcGetThisDebug(pid, procPtrPtr)
  448.     Proc_PID        pid;
  449.     Proc_ControlBlock    **procPtrPtr;
  450. {
  451.     register Proc_ControlBlock     *procPtr;
  452.     ReturnStatus        status;
  453.  
  454.  
  455.     LOCK_MONITOR;
  456.     status = SUCCESS;
  457.     while (TRUE) {
  458.     procPtr = Proc_LockPID(pid);
  459.     if (procPtr == (Proc_ControlBlock *) NIL ||
  460.         (procPtr->genFlags & PROC_DYING)) {
  461.         /*
  462.          * The pid they gave us either doesn't exist or the
  463.          * corresponding process is exiting.
  464.          */
  465.         if (procPtr != (Proc_ControlBlock *) NIL) {
  466.         Proc_Unlock(procPtr);
  467.         }
  468.         status = PROC_INVALID_PID;
  469.         goto exit;
  470.     }
  471.     procPtr->genFlags |= PROC_DEBUG_WAIT;
  472.  
  473.     if (procPtr->state == PROC_SUSPENDED) {
  474.         procPtr->genFlags &= ~PROC_DEBUG_WAIT;
  475.         procPtr->genFlags |= PROC_DEBUGGED;
  476.         if (procPtr->genFlags & PROC_ON_DEBUG_LIST) {
  477.         List_Remove((List_Links *) procPtr);
  478.         procPtr->genFlags &= ~PROC_ON_DEBUG_LIST;
  479.         }
  480.         goto exit;
  481.     }
  482.  
  483.     Proc_Unlock(procPtr);
  484.     if (Sync_Wait(&debugListCondition, TRUE)) {
  485.         Proc_Lock(procPtr);
  486.         procPtr->genFlags &= ~PROC_DEBUG_WAIT;
  487.         Proc_Unlock(procPtr);
  488.         status = GEN_ABORTED_BY_SIGNAL;
  489.         goto exit;
  490.     }
  491.     }
  492. exit:
  493.     *procPtrPtr = procPtr;
  494.     UNLOCK_MONITOR;
  495.     return(status);
  496. }
  497.  
  498. /*
  499.  *----------------------------------------------------------------------
  500.  *
  501.  * ProcGetNextDebug --
  502.  *
  503.  *    Look through the list of debuggable processes and get the
  504.  *    first one that hasn't been debugged yet. Wait for one if
  505.  *    there aren't any.
  506.  *
  507.  * Results:
  508.  *    SYS_ARG_NOACCESS if data couldn't be copied to user address space.
  509.  *    GEN_ABORTED_BY_SIGNAL if wait for process was interrupted by a 
  510.  *        signal
  511.  *
  512.  * Side effects:
  513.  *    Process is removed from list, process id is copied to user variable
  514.  *
  515.  *----------------------------------------------------------------------
  516.  */
  517.  
  518. static ENTRY ReturnStatus
  519. ProcGetNextDebug(destAddr, procPtrPtr)
  520.     Address        destAddr;
  521.     Proc_ControlBlock    **procPtrPtr;
  522. {
  523.     Boolean            sigPending = FALSE;
  524.     register Proc_ControlBlock     *procPtr = (Proc_ControlBlock *) NIL;
  525.     ReturnStatus        status;
  526.  
  527.  
  528.     LOCK_MONITOR;
  529.  
  530.     status = SUCCESS;
  531.     while (!sigPending) {
  532.     if (!List_IsEmpty(debugList)) {
  533.         procPtr = (Proc_ControlBlock *) List_First(debugList);
  534.         Proc_Lock(procPtr);
  535.         procPtr->genFlags |= PROC_DEBUGGED;
  536.         List_Remove((List_Links *) procPtr);
  537.         procPtr->genFlags &= ~PROC_ON_DEBUG_LIST;
  538.         break;
  539.     }
  540.     sigPending = Sync_Wait(&debugListCondition, TRUE);
  541.     }
  542.     if (!sigPending) {
  543.     if ((Vm_CopyOut(sizeof(Proc_PID), 
  544.           (Address) &procPtr->processID, destAddr)) != SUCCESS){
  545.         status = SYS_ARG_NOACCESS;
  546.     }
  547.     } else {
  548.     status = GEN_ABORTED_BY_SIGNAL;
  549.     }
  550.     *procPtrPtr = procPtr;
  551.     UNLOCK_MONITOR;
  552.     return(status);
  553. }
  554.  
  555. /*
  556.  *----------------------------------------------------------------------
  557.  *
  558.  * AddToDebugList --
  559.  *
  560.  *    Adds the given process to the debug list.
  561.  *
  562.  * Results:
  563.  *    None.
  564.  *
  565.  * Side effects:
  566.  *    Process is added to list, process genFlags is modified.
  567.  *
  568.  *----------------------------------------------------------------------
  569.  */
  570.  
  571. static ENTRY void
  572. AddToDebugList(procPtr)
  573.     register Proc_ControlBlock     *procPtr;
  574. {
  575.     LOCK_MONITOR;
  576.  
  577.     List_Insert((List_Links *) procPtr, LIST_ATREAR(debugList));
  578.     procPtr->genFlags |= PROC_ON_DEBUG_LIST;
  579.  
  580.     UNLOCK_MONITOR;
  581. }
  582.  
  583. /*
  584.  *----------------------------------------------------------------------
  585.  *
  586.  * RemoveFromDebugList --
  587.  *
  588.  *    Removes the given process from the debug list.
  589.  *
  590.  * Results:
  591.  *    None.
  592.  *
  593.  * Side effects:
  594.  *    The process is removed from the list, process's genFlags field
  595.  *    is modified.
  596.  *
  597.  *----------------------------------------------------------------------
  598.  */
  599.  
  600. static ENTRY void
  601. RemoveFromDebugList(procPtr)
  602.     register Proc_ControlBlock     *procPtr;
  603. {
  604.     LOCK_MONITOR;
  605.  
  606.     if (procPtr->genFlags & PROC_ON_DEBUG_LIST) {
  607.     List_Remove((List_Links *) procPtr);
  608.     procPtr->genFlags &= ~PROC_ON_DEBUG_LIST;
  609.     }
  610.  
  611.     UNLOCK_MONITOR;
  612. }
  613.  
  614.